﻿using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Nuts
{
    public class BushConfig
    {
        public BushConfig(uint layersCount)
        {
            layers = new BushLayerConfig[layersCount];
        }

        public Texture2D texture = null;
        public BushLayerConfig[] layers;
        public SoundEffect sound;
    }

    public class BushLayerConfig
    {
        public Rectangle srcRect;
        public Vector2 position;
        public Vector2 rotationOrigin;
    }

    public class Bush
    {
        public static readonly Vector2 ScaleRestLength = new Vector2(1.0f, 1.0f);
        public static readonly Vector2 ScaleOscK = new Vector2(100.0f, 150.0f);
        public static readonly Vector2 ScaleOscDamping = new Vector2(2.0f, 2.0f);

        public Bush(BushConfig config, Vector2 position)
        {
            System.Diagnostics.Debug.Assert(config != null);

            m_position = position;
            m_config = config;
            m_layers = new BushLayer[m_config.layers.Length];
        }

        public void Initialize()
        {
            for (int layerIt = 0; layerIt < m_config.layers.Length; ++layerIt)
            {
                m_layers[layerIt] = new BushLayer();
                m_layers[layerIt].m_scale = new Vector2(1.0f, 1.0f);
                m_layers[layerIt].m_scaleSpeed = new Vector2(0.0f, 0.0f);
                m_layers[layerIt].m_scaleForce = new Vector2(0.0f, 0.0f);
            }
        }

        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            System.Diagnostics.Debug.Assert(m_config.texture != null);

            BushLayer layer;
            BushLayerConfig layerConfig;

            for (int layerIt = 0; layerIt < m_config.layers.Length; ++layerIt)
            {
                layer = m_layers[layerIt];
                layerConfig = m_config.layers[layerIt];

                spriteBatch.Draw(m_config.texture, layer.m_spritePosition, layerConfig.srcRect,
                    Color.White, layer.m_rotation, layerConfig.rotationOrigin, layer.m_scale, SpriteEffects.None, 0.0f);
            }
        }
        
        public void Update(GameTime gameTime)
        {
            float deltaT = (float)gameTime.ElapsedGameTime.TotalSeconds;
            
            BushLayer layer;
            BushLayerConfig layerConfig;

            Vector2 min = m_position;
            Vector2 max = m_position;

            for (int layerIt = 0; layerIt < m_config.layers.Length; ++layerIt)
            {
                layer = m_layers[layerIt];

                layerConfig = m_config.layers[layerIt];

                layer.m_scaleForce.X = (ScaleRestLength.X - layer.m_scale.X) * ScaleOscK.X +
                    layer.m_scaleSpeed.X * -ScaleOscDamping.X;
                layer.m_scaleForce.Y = (ScaleRestLength.Y - layer.m_scale.Y) * ScaleOscK.Y +
                    layer.m_scaleSpeed.Y * -ScaleOscDamping.Y;

                layer.m_scaleSpeed.X += layer.m_scaleForce.X * deltaT;
                layer.m_scaleSpeed.Y += layer.m_scaleForce.Y * deltaT;

                layer.m_scale.X = layer.m_scale.X + deltaT * layer.m_scaleSpeed.X;
                layer.m_scale.Y = layer.m_scale.Y + deltaT * layer.m_scaleSpeed.Y;

                layer.m_spritePosition.X = m_position.X + layerConfig.position.X * layer.m_scale.X;
                layer.m_spritePosition.Y = m_position.Y + layerConfig.position.Y * layer.m_scale.Y;

                if (layer.m_spritePosition.X < min.X)
                {
                    min.X = layer.m_spritePosition.X;
                }
                if (layer.m_spritePosition.Y < min.Y)
                {
                    min.Y = layer.m_spritePosition.Y;
                }
                if (layer.m_spritePosition.X + (float)layerConfig.srcRect.Width * layer.m_scale.X > max.X)
                {
                    max.X = layer.m_spritePosition.X + (float)layerConfig.srcRect.Width * layer.m_scale.X;
                }
                if (layer.m_spritePosition.Y + (float)layerConfig.srcRect.Height * layer.m_scale.Y > max.Y)
                {
                    max.Y = layer.m_spritePosition.Y + (float)layerConfig.srcRect.Height * layer.m_scale.Y;
                }
            }

            m_hitBox.X = (int)min.X;
            m_hitBox.Y = (int)min.Y;
            m_hitBox.Width = (int)(max.X - min.X);
            m_hitBox.Height = (int)(max.Y - min.Y);
        }

        public bool OnSlap(int x, int y)
        {
            Random rnd = new Random();

            if (m_hitBox.Contains(x, y))
            {
                m_config.sound.Play();

                BushLayer layer;

                for (int layerIt = 0; layerIt < m_config.layers.Length; ++layerIt)
                {
                    layer = m_layers[layerIt];
                    layer.m_scaleSpeed.X += -1.0f + (float)(layerIt + 1) * 0.5f * (0.5f * (float)rnd.NextDouble() - 1.0f);
                    layer.m_scaleSpeed.Y += -1.0f + (float)(layerIt + 1) * 0.5f * (0.5f * (float)rnd.NextDouble() - 1.0f);
                }

                return true;
            }

            return false;
        }

        public Rectangle HitBox
        {
            get { return m_hitBox; }
        }

        private BushConfig m_config;
        private BushLayer[] m_layers = null;
        private Rectangle m_hitBox;
        private Vector2 m_position;
    }

    public class BushLayer
    {
        public Vector2 m_spritePosition;
        public float m_rotation = 0.0f;
        public Vector2 m_scale;
        public Vector2 m_scaleSpeed;
        public Vector2 m_scaleForce;
    }
}
